﻿using CommonUtils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LAKALA.Models;

namespace WindowsForms拉卡拉支付
{
    public partial class Form1 : Form
    {
        System.Timers.Timer _tmrRemeber;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            RemForm.ReadRememberForm(this, null);

            _tmrRemeber = new System.Timers.Timer();
            _tmrRemeber.Elapsed += new System.Timers.ElapsedEventHandler(_tmrRemeber_Elapsed);
            _tmrRemeber.Interval = 10 * 1000;
            _tmrRemeber.Start();

        }

        void _tmrRemeber_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                RemForm.RememberForm(this, null);
            }
            catch (Exception ex)
            {
                //MessageBox.Show("_tmrRemeber_Elapsed" + ex.Message);
            }
        }

        private void btnReadCrt_Click(object sender, EventArgs e)
        {
            try
            {
                if (ofdCrt.ShowDialog() == DialogResult.OK)
                {
                    X509Certificate2 cert = new X509Certificate2(ofdCrt.FileName);
                    txtCertSN.Text = cert.SerialNumber;
                    //txtCertSN10.Text = cert.SerialNumber.ToLower();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        private void btnMicroPay_Click(object sender, EventArgs e)
        {
            try
            {
                JsonSerializerSettings jsetting = new JsonSerializerSettings();
                jsetting.DefaultValueHandling = DefaultValueHandling.Ignore;

                if (decimal.Parse(txtAmt.Text) >= 1M)
                {
                    DialogResult dr = MessageBox.Show("金额过大，是否继续？", "OO", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (dr == DialogResult.No)
                    {
                        return;
                    }
                }
                if (string.IsNullOrWhiteSpace(txtAuthCode.Text))
                {
                    MessageBox.Show("付款码不能为空！");
                    return;
                }

                int total_fee = VString.TryInt((VString.TryDec(txtAmt.Text.Trim()) * 100));
                txtOutTradeNo.Text = "S" + DateTime.Now.ToString("yyyyMMddHHmmssfff");

                MicroPayReq req = new MicroPayReq();
                req.mercId = txtMchNo.Text.Trim();
                req.termNo = txtTermNo.Text.Trim();
                req.authCode = txtAuthCode.Text.Trim();
                req.amount = total_fee.ToString();
                req.orderId = txtOutTradeNo.Text;
                req.subject = "条码支付-总部";

                LKL_PubReq<MicroPayReq> pub = new LKL_PubReq<MicroPayReq>();                
                pub.reqData = req;

                string bodyJson = JsonConvert.SerializeObject(pub, jsetting);
                bodyJson = bodyJson.Substring(0, bodyJson.Length - 1);
                //空termExtInfo处理
                bodyJson = bodyJson + ",\"termExtInfo\":{}}";

                #region 生成签名

                string appid = txtAppId.Text;
                string serial_no = txtCertSN.Text;
                String Authorization = GetSign(appid, serial_no, bodyJson);

                #endregion

                Dictionary<string, string> dicHeader = new Dictionary<string, string>();
                dicHeader.Add("Authorization", Authorization);

                string mainUrl = txtMainUrl.Text;
                string url = mainUrl + "/labs_order_micropay";
                GLog.WLog("url:" + url);
                GLog.WLog("Authorization:" + Authorization);
                GLog.WLog("请求报文:" + bodyJson);
                Dictionary<string, string> rspHeader = new Dictionary<string, string>();

                var rstStr = HttpUtil.HttpPostJson(url, bodyJson, dicHeader, 30, rspHeader);
                GLog.WLog("响应报文:" + rstStr);
                txtRst.Text = rstStr;
                if (!ValidSign(rspHeader, rstStr, txtPubCert.Text))
                {
                    MessageBox.Show("签名验证失败");
                }
                txtAuthCode.Clear();

                var rspMA = JsonConvert.DeserializeObject<LKL_PubRsp<MicroPayRsp>>(rstStr);
                var rspM = rspMA.respData;
                if (rspMA.cmdRetCode == "GLOBAL_SUCCESS")
                {
                    lblPayStatus.Text = "支付成功";
                }
                else if (rspMA.cmdRetCode == "TRANS_USING_PAYING")
                {
                    lblPayStatus.Text = "支付中";
                }
                else
                {
                    lblPayStatus.Text = "支付失败";
                }
                if (rspM != null)
                {
                    if(!string.IsNullOrWhiteSpace(rspM.lklOrderId))
                        txtTradeNo.Text = rspM.lklOrderId;
                    if (!string.IsNullOrWhiteSpace(rspM.weOrderNo))
                        txtThirdTradeNo.Text = rspM.weOrderNo;

                    DateTime dtTimeEnd = DateTime.Now;
                    if (!string.IsNullOrWhiteSpace(rspM.tradeTime))
                    {
                        try
                        {
                            dtTimeEnd = DateTime.ParseExact(rspM.tradeTime, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
                        }
                        catch { }
                    }
                    txtPayTime.Text = dtTimeEnd.ToString("yyyy-MM-dd HH:mm:ss");
                    // 分转元：
                    if (!string.IsNullOrEmpty(rspM.amount))
                    {
                        string total_amount = (VString.TryInt(rspM.amount) / 100M).ToString("F2");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public string GetSign(string appid, string serial_no, string bodyJson)
        {
            /*
                 将分配的appId、证书序列号、时间戳、随机字符串、请求报文拼接。拼接报文一共有5行，每一行为一个参数。行尾以\n（换行符，ASCII编码值为0x0A）结束，包括最后一行。

具体格式如下：
${appid}\n+${serialNo}\n+${timeStamp}\n+${nonceStr}\n+${body}\n
                 */

            string timestamp = TimeStampUtil.GetTimeStampTen().ToString();//10位和13位的都可以 
            string nonce_str = Guid.NewGuid().ToString("N").Substring(12);

            StringBuilder sc = new StringBuilder();
            sc.AppendFormat("{0}\n", appid);
            sc.AppendFormat("{0}\n", serial_no);
            sc.AppendFormat("{0}\n", timestamp);
            sc.AppendFormat("{0}\n", nonce_str);
            sc.AppendFormat("{0}\n", bodyJson);
            string fnstr = sc.ToString();

            var rsaP = RsaUtil.LoadPrivateKey(txtPrivateKey.Text, "PKCS8");
            byte[] data = Encoding.UTF8.GetBytes(fnstr);//待签名字符串转成byte数组，UTF8
            byte[] byteSign = rsaP.SignData(data, "SHA256");//对应JAVA的RSAwithSHA256
            string sign = Convert.ToBase64String(byteSign);//签名byte数组转为BASE64字符串

            string schema = "LKLAPI-SHA256withRSA";
            String token = "appid=\"" + appid + "\",serial_no=\"" + serial_no + "\",timestamp=\"" + timestamp
            + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\"";
            String authorization = schema + " " + token;
            return authorization;
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="rspHeader">HTTP响应头</param>
        /// <param name="rspBody">响应报文</param>
        /// <param name="pubCert">公钥证书</param>
        /// <returns></returns>
        bool ValidSign(IDictionary<string, string> rspHeader, string rspBody, string pubCert)
        {
            string appid = "";
            string serial_no = "";
            string timestamp = "";
            string nonce_str = "";
            string rspSign = "";

            foreach (var item in rspHeader)
            {
                if (item.Key == "Lklapi-Appid")
                    appid = item.Value;

                if (item.Key == "Lklapi-Serial")
                    serial_no = item.Value;

                if (item.Key == "Lklapi-Timestamp")
                    timestamp = item.Value;

                if (item.Key == "Lklapi-Nonce")
                    nonce_str = item.Value;

                if (item.Key == "Lklapi-Signature")
                    rspSign = item.Value;
            }

            StringBuilder sc = new StringBuilder();
            sc.AppendFormat("{0}\n", appid);
            sc.AppendFormat("{0}\n", serial_no);
            sc.AppendFormat("{0}\n", timestamp);
            sc.AppendFormat("{0}\n", nonce_str);
            sc.AppendFormat("{0}\n", rspBody);
            string fnstr = sc.ToString();

            byte[] byteCon = Encoding.UTF8.GetBytes(fnstr);

            byte[] byteRspSign = Convert.FromBase64String(rspSign);
            var rsaPub = RsaUtil.LoadPublicCert(pubCert);

            bool bRst = rsaPub.VerifyData(byteCon, "SHA256", byteRspSign);

            return bRst;

        }

        private void txtAuthCode_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                btnMicroPay_Click(sender, e);
            }
        }

        private void btnOrderQuery_Click(object sender, EventArgs e)
        {
            try
            {
                JsonSerializerSettings jsetting = new JsonSerializerSettings();
                jsetting.DefaultValueHandling = DefaultValueHandling.Ignore;

                int total_fee = VString.TryInt((VString.TryDec(txtAmt.Text.Trim()) * 100));                 

                var req = new OrderQueryReq();
                req.mercId = txtMchNo.Text.Trim();
                req.termNo = txtTermNo.Text.Trim();
                req.ornOrderId = txtOutTradeNo.Text;

                var pub = new LKL_PubReq<OrderQueryReq>();                
                pub.reqData = req;

                string bodyJson = JsonConvert.SerializeObject(pub, jsetting);
                bodyJson = bodyJson.Substring(0, bodyJson.Length - 1);
                //空termExtInfo处理
                bodyJson = bodyJson + ",\"termExtInfo\":{}}";

                #region 生成签名

                string appid = txtAppId.Text;
                string serial_no = txtCertSN.Text;
                String Authorization = GetSign(appid, serial_no, bodyJson);

                #endregion

                Dictionary<string, string> dicHeader = new Dictionary<string, string>();
                dicHeader.Add("Authorization", Authorization);

                string mainUrl = txtMainUrl.Text;
                string url = mainUrl + "/labs_order_query";
                GLog.WLog("url:" + url);
                GLog.WLog("Authorization:" + Authorization);
                GLog.WLog("请求报文:" + bodyJson);
                Dictionary<string, string> rspHeader = new Dictionary<string, string>();

                var rstStr = HttpUtil.HttpPostJson(url, bodyJson, dicHeader, 30, rspHeader);
                GLog.WLog("响应报文:" + rstStr);
                txtRst.Text = rstStr;
                if (!ValidSign(rspHeader, rstStr, txtPubCert.Text))
                {
                    MessageBox.Show("签名验证失败");
                }
                 

                var rspMA = JsonConvert.DeserializeObject<LKL_PubRsp<OrderQueryRsp>>(rstStr);
                var rspM = rspMA.respData;
                
                if (rspM != null)
                {
                    if (rspM.tradeState == "SUCCESS")
                    {
                        lblPayStatus.Text = "支付成功";
                    }
                    else if (rspM.tradeState == "DEAL")
                    {
                        lblPayStatus.Text = "支付中";
                    }
                    else
                    {
                        lblPayStatus.Text = "支付失败";
                    }

                    if (!string.IsNullOrWhiteSpace(rspM.lklOrderNo))
                        txtTradeNo.Text = rspM.lklOrderNo;

                    if (!string.IsNullOrWhiteSpace(rspM.weOrderNo))
                        txtThirdTradeNo.Text = rspM.weOrderNo;

                    DateTime dtTimeEnd = DateTime.Now;
                    if (!string.IsNullOrWhiteSpace(rspM.tradeTime))
                    {
                        try
                        {
                            dtTimeEnd = DateTime.ParseExact(rspM.tradeTime, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
                        }
                        catch { }
                    }
                    txtPayTime.Text = dtTimeEnd.ToString("yyyy-MM-dd HH:mm:ss");
                    // 分转元：
                    if (!string.IsNullOrEmpty(rspM.amount))
                    {
                        string total_amount = (VString.TryInt(rspM.amount) / 100M).ToString("F2");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnRefund_Click(object sender, EventArgs e)
        {
            try
            {
                JsonSerializerSettings jsetting = new JsonSerializerSettings();
                jsetting.DefaultValueHandling = DefaultValueHandling.Ignore;

                int refund_fee = VString.TryInt((VString.TryDec(txtRefundAmt.Text ) * 100));                 
                txtOutRefundNo.Text = "R" + DateTime.Now.ToString("yyyyMMddHHmmssfff");

                var req = new RefundReq();
                req.mercId = txtMchNo.Text.Trim();
                req.termNo = txtTermNo.Text.Trim();
                req.ornOrderId = txtOutTradeNo.Text;//原商户单号
                req.refundOrderId = txtOutRefundNo.Text;//退款申请号
                req.amount = refund_fee.ToString();//退款金额

                var pub = new LKL_PubReq<RefundReq>();
                pub.reqData = req;

                string bodyJson = JsonConvert.SerializeObject(pub, jsetting);
                bodyJson = bodyJson.Substring(0, bodyJson.Length - 1);
                //空termExtInfo处理
                bodyJson = bodyJson + ",\"termExtInfo\":{}}";

                #region 生成签名

                string appid = txtAppId.Text;
                string serial_no = txtCertSN.Text;
                String Authorization = GetSign(appid, serial_no, bodyJson);

                #endregion

                Dictionary<string, string> dicHeader = new Dictionary<string, string>();
                dicHeader.Add("Authorization", Authorization);

                string mainUrl = txtMainUrl.Text;
                string url = mainUrl + "/labs_order_refund";
                GLog.WLog("url:" + url);
                GLog.WLog("Authorization:" + Authorization);
                GLog.WLog("请求报文:" + bodyJson);
                Dictionary<string, string> rspHeader = new Dictionary<string, string>();

                var rstStr = HttpUtil.HttpPostJson(url, bodyJson, dicHeader, 30, rspHeader);
                GLog.WLog("响应报文:" + rstStr);
                txtRst.Text = rstStr;
                if (!ValidSign(rspHeader, rstStr, txtPubCert.Text))
                {
                    MessageBox.Show("签名验证失败");
                }                

                var rspMA = JsonConvert.DeserializeObject<LKL_PubRsp<OrderQueryRsp>>(rstStr);
                var rspM = rspMA.respData;

                if (rspMA.cmdRetCode == "GLOBAL_SUCCESS")
                {
                    lblRefundStatus.Text = "退款申请成功";
                }                 
                else
                {
                    lblRefundStatus.Text = "退款失败";
                }

                if (rspM != null)
                {
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnRefundQuery_Click(object sender, EventArgs e)
        {
            try
            {
                JsonSerializerSettings jsetting = new JsonSerializerSettings();
                jsetting.DefaultValueHandling = DefaultValueHandling.Ignore;

                int total_fee = VString.TryInt((VString.TryDec(txtAmt.Text.Trim()) * 100));

                var req = new OrderQueryReq();
                req.mercId = txtMchNo.Text.Trim();
                req.termNo = txtTermNo.Text.Trim();
                req.ornOrderId = txtOutRefundNo.Text;//传入退款申请号

                var pub = new LKL_PubReq<OrderQueryReq>();
                pub.reqData = req;

                string bodyJson = JsonConvert.SerializeObject(pub, jsetting);
                bodyJson = bodyJson.Substring(0, bodyJson.Length - 1);
                //空termExtInfo处理
                bodyJson = bodyJson + ",\"termExtInfo\":{}}";

                #region 生成签名

                string appid = txtAppId.Text;
                string serial_no = txtCertSN.Text;
                String Authorization = GetSign(appid, serial_no, bodyJson);

                #endregion

                Dictionary<string, string> dicHeader = new Dictionary<string, string>();
                dicHeader.Add("Authorization", Authorization);

                string mainUrl = txtMainUrl.Text;
                string url = mainUrl + "/labs_order_query";
                GLog.WLog("url:" + url);
                GLog.WLog("Authorization:" + Authorization);
                GLog.WLog("请求报文:" + bodyJson);
                Dictionary<string, string> rspHeader = new Dictionary<string, string>();

                var rstStr = HttpUtil.HttpPostJson(url, bodyJson, dicHeader, 30, rspHeader);
                GLog.WLog("响应报文:" + rstStr);
                txtRst.Text = rstStr;
                if (!ValidSign(rspHeader, rstStr, txtPubCert.Text))
                {
                    MessageBox.Show("签名验证失败");
                }

                var rspMA = JsonConvert.DeserializeObject<LKL_PubRsp<OrderQueryRsp>>(rstStr);
                var rspM = rspMA.respData;

                if (rspM != null)
                {
                    //除了退款成功，其它状态未能验证
                    if (rspM.tradeState == "SUCCESS")
                    {
                        lblRefundStatus.Text = "退款成功";
                    }
                    else if (rspM.tradeState == "DEAL")
                    {
                        lblRefundStatus.Text = "退款中";
                    }
                    else
                    {
                        lblRefundStatus.Text = "退款失败";
                    }

                    if (!string.IsNullOrWhiteSpace(rspM.lklOrderNo))
                        txtTradeNo.Text = rspM.lklOrderNo;

                    if (!string.IsNullOrWhiteSpace(rspM.weOrderNo))
                        txtThirdTradeNo.Text = rspM.weOrderNo;

                     
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
